package com.wwg.cms.util;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 反射工具包
 *
 * @author 王文磊
 * @version $Id: ReflectUtils.java 20 2010-08-31 15:37:26Z sanshi2 $
 * @date 2008-6-22 18:10:37
 */
public class ReflectUtils {
    protected static Object[] nullarray = new Object[]{};

    private static Log logger = LogFactory.getLog(ReflectUtils.class);


    /**
     * 得到传入参数的具体类型；
     *
     * @param obj：Object
     * @return 参数的具体类型
     */
    public static String getDataType(Object obj) {
        if (obj == null) {
            return null;
        }

        String type = obj.getClass().getName();

        int pos = type.lastIndexOf(".");
        if (pos >= 0) {
            type = type.substring(pos + 1);
        }

        return type;
    }

    /**
     * getValue 获取值对象
     *
     * @param object 取值源对象
     * @return 值对象
     */
    public static Object getValue(Object object, String getName) {
        Object value = null;
        try {
            Method getMethod = object.getClass().getMethod(getName, new Class[]{});
            value = getMethod.invoke(object, nullarray);
        } catch (Exception ex) {
//            logger.error("获取值对象错误", ex);
        }
        return value;
    }


    /**
     * setValue 设置值对象
     *
     * @param object  要设置的目标对象
     * @param value   要设置的值
     * @param setName 设置方法名
     * @param clas    class参数数组
     */
    public static void setValue(Object object, Object value, String setName, Class[] clas) {
        try {
            Object[] param = {value};
            Method setMethod = object.getClass().getMethod(setName, clas);
            setMethod.invoke(object, param);
        }
        catch (Exception ex) {
            logger.error("设置值对象错误 ", ex);
        }
    }

    /**
     * 取对象的属性值优先取对象的get方法返回值然后取字段，
     * 可以强制取私有字段的值
     *
     * @param obj
     * @param name
     * @return
     */
    public static Object getProperty(Object obj, String name) {
        java.lang.reflect.Method[] methods = obj.getClass().getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            String mnl = method.getName().toLowerCase();
            if (mnl.equals("get" + name.toLowerCase()) && method.getParameterTypes().length == 0) {
                try {
                    return method.invoke(obj, new Object[]{});
                } catch (IllegalAccessException e) {
                    logger.error("", e);
                } catch (InvocationTargetException e) {
                    logger.error("", e);
                }
            }
        }
        try {
            return obj.getClass().getField(name).get(obj);
        } catch (IllegalAccessException e) {

        } catch (NoSuchFieldException e) {
        }
        logger.error("can't get the property[" + name + "] from public method or field try get vaule from the protected and private field");
        return getFiledVaule(obj, obj.getClass(), name);
    }

    private static Object getFiledVaule(Object obj, Class clazz, String name) {
        Field[] fields = clazz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            if (field.getName().equals(name)) {
                try {
                    field.setAccessible(true);
                    return field.get(obj);
                } catch (Exception e1) {
                    logger.error("", e1);
                }
            }
        }
        if (clazz.getSuperclass() != null) {
            return getFiledVaule(obj, clazz.getSuperclass(), name);
        }
        return null;
    }

    public static List getGetMethodList(String className) {
        Class clazz = null;
        try {
            clazz = Class.forName(className);
            return getGetMethodList(clazz);
        } catch (ClassNotFoundException e) {
            logger.error("ClassNotFoundException", e);
        }
        return null;
    }

    public static List getGetMethodList(Class aClass) {
        List list = new ArrayList();
        java.lang.reflect.Method[] methods = aClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            String mnl = method.getName();
            if (mnl.startsWith("get")) {
                Class[] types = method.getParameterTypes();
                if (types == null || types.length == 0) {
                    String nl = mnl.charAt(3) + "";
                    list.add(nl.toLowerCase() + mnl.substring(4));
                }
            }
        }
        return list;
    }
    public static Object getServiceValue(Object service,String method,Object[] args){
        List <Method> ls=getObjectMethod(service,method,args.length);
        for (int i = 0; i < ls.size(); i++) {
            Method method1 = ls.get(i);
            try{
              Object ob=  method1.invoke(service,convertArgs(method1,args));
              return ob;
            }catch (Exception e){

            }
        }
      return null;
    }
    private static Object[] convertArgs(Method method,Object[] args){
        Object[] objects=new Object[args.length];
      Class[] tps=  method.getParameterTypes();
        for (int i = 0; i < tps.length; i++) {
            Class tp = tps[i];
            if(tp.isInstance(args[i])){
               objects[i]=args[i];
            }else{
               objects[i]=tryConvertObject(args[i],tp);
            }
        }
        return objects;
    }
    private static Object tryConvertObject(Object obj,Class toClass){
        if(obj==null) return null;
        String s=null;
        if(obj instanceof String) s= (String) obj;
        else s=obj.toString();
       return BeanUtilsBean.getInstance().getConvertUtils().convert(s,toClass);
    }
    public static List<Method> getObjectMethod(Object obj,String methodName,int argsize){
        List <Method> ls=new ArrayList<Method>();
               Method[] methods = obj.getClass().getMethods();

        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            if(method.getName().equals(methodName)) {
                if(method.getParameterTypes().length==argsize){
                    ls.add(method);
                }
            }
        }
        return ls;
    }
    public static Object getPropertysValue(Object o, String propertys) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        PropertyUtilsBean utilsBean = BeanUtilsBean.getInstance().getPropertyUtils();
        return utilsBean.getProperty(o, propertys);
    }

    public static void depCopy(Object ref, Object dest) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {

        depCopy(ref, dest, dest.getClass().getClassLoader());

    }

    public static void depCopy(Object ref, Object dest, ClassLoader loader) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
        PropertyUtilsBean utilsBean = BeanUtilsBean.getInstance().getPropertyUtils();
        PropertyDescriptor origDescriptors[] = utilsBean.getPropertyDescriptors(ref);
        //   utilsBean.copyProperties("", "");
        for (int i = 0; i < origDescriptors.length; i++) {
            String name = origDescriptors[i].getName();
            if (utilsBean.isReadable(ref, name)) {
                if (utilsBean.isWriteable(dest, name)) {
                    Object value = utilsBean.getSimpleProperty(ref, name);
                    Object newValue = value;
                    if (value != null && value.getClass().getName().startsWith("com.css")) {
                        String cn = value.getClass().getName();
                        // Class newT = utilsBean.getPropertyType(dest, name);
                        // if (cn.equals(newT.getName())) {
                        //     newValue = newT.newInstance();
                        //   } else {
                        try {
                            logger.debug("newT = " + cn);
                            newValue = Class.forName(cn, true, loader).newInstance();
                        } catch (ClassNotFoundException e) {
                        }
                        //  }
                        depCopy(value, newValue, loader);
                    }
                    if (logger.isDebugEnabled())
                        logger.debug("set:" + name + " class:" + (newValue == null ? "" : newValue.getClass().getClassLoader() + " old:" + value.getClass().getClassLoader()));
                    utilsBean.setSimpleProperty(dest, name, newValue);
                }
            }

        }
    }
    /*
    final static public byte[] getDataSource(InputStream is) {
        if (is == null) {
            return null;
        }
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] arrayByte = null;
        try {
            byte[] bytes = new byte[8192];
            bytes = new byte[is.available()];
            int read;
            while ((read = is.read(bytes)) >= 0) {
                byteArrayOutputStream.write(bytes, 0, read);
            }
            arrayByte = byteArrayOutputStream.toByteArray();
        } catch (Exception e) {
            return null;
        } finally {
            try {
                if (byteArrayOutputStream != null) {
                    byteArrayOutputStream.close();
                    byteArrayOutputStream = null;
                }
                if (is != null) {
                    is.close();
                    is = null;
                }

            } catch (IOException e) {
            }
        }
        return arrayByte;
    }

    static class LA extends ClassLoader {
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
          //  if(!name.equals("com.css.hr.entity.PersonRoleEntity")) return super.findClass(name);
            byte[] bs = getDataSource(this.getResourceAsStream(name.replace(".","/")+".class"));
            return defineClass(name, bs, 0, bs.length);
        }

        public Class getMyClass(String name) {
            try {
                return findClass(name);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    class LB extends ClassLoader {

    }

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ClassNotFoundException {

       LA la=new LA();
        Class aClass=la.getMyClass("com.css.hr.entity.PersonRoleEntity");
         Class bClass =la.getMyClass("com.css.hr.entity.PersonEntity");

        Object personRoleEntity = aClass.newInstance();
        Object personEntity = bClass.newInstance();
        BeanUtils.setProperty(personEntity,"name","wwl");
        BeanUtils.setProperty(personRoleEntity,"person",personEntity);
      //  personEntity.setName("wwl");
      //  personRoleEntity.setPerson(personEntity);
        System.out.println("personEntity = " + BeanUtils.getProperty(personRoleEntity,"person"));
        PersonRoleEntity newO = new PersonRoleEntity();
        ReflectUtils.depCopy(personRoleEntity, newO);
      
        System.out.println("newO.getPerson() = " + newO);
    }
    */

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        Map map = new HashMap();
        Map map2 = new HashMap();
        map.put("mymap", map2);
        map.put("aaa","my a value");
        map2.put("kkk", "lllllllll");
        map2.put("kkk",map);
        String str = (String) getPropertysValue(map, "mymap.kkk.mymap.kkk.aaa");
        System.out.println("str = " + str);


    }

}